/*
Copyright 2007 John Tsiombikas <nuclear@siggraph.org>

This file is part of the pixelshow 2007 invitation demo.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <GL/glew.h>
#include <SDL.h>
#include "text.h"
#include "text_ml.h"
#include "parts.h"
#include "image.h"
#include "timings.h"
#include "sdlvf.h"

#if defined(WIN32) || defined(__WIN32__)
#include <windows.h>
#endif

int init(void);
int process_events(void);
void redraw(void);
void draw_splash(void);
void startup_text(const char *txt);
void parse_args(int argc, char **argv);

extern void text_key_handler(int key);

int xsz = 1024, ysz = 768;
int fullscr = 1;
int music = 1;
int num_ducks = 4;

static unsigned int start_time = 0;
static unsigned int startup_font;

static unsigned int splash_tex;
static float splash_alpha = 0.0;

int main(int argc, char **argv)
{
	parse_args(argc, argv);

	if(init() == -1) {
		SDL_Quit();
		return 1;
	}
	start_time = SDL_GetTicks();

	while(process_events());
	SDL_Quit();
	return 0;
}

#define MIN(a, b)	((a) < (b) ? (a) : (b))
int init(void)
{
	void *img;
	int img_x, img_y;
	unsigned int load_start;

	int bpp = 32;
	if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) == -1) {
		fprintf(stderr, "failed to initialize sdl\n");
		return -1;
	}

	if(!fullscr) {
		bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
	}
	SDL_GL_SetAttribute(SDL_GL_RED_SIZE, bpp >= 24 ? 8 : 5);
	SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, bpp >= 24 ? 8 : 6);
	SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, bpp >= 24 ? 8 : 5);
	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
	SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

	if(!SDL_SetVideoMode(xsz, ysz, bpp, SDL_OPENGL | (fullscr ? SDL_FULLSCREEN : 0))) {
		fprintf(stderr, "failed to initialize graphics\n");
		return -1;
	}
	SDL_EnableKeyRepeat(300, 20);
	SDL_WM_SetCaption("Pixelshow 2007 Invitation / The Lab Demos", 0);
	SDL_ShowCursor(0);

	glewInit();

	if(!glCreateProgram || !glCreateShader) {
		const char *msg = {
			"This demo needs GLSL support (pixel shaders 2.0)\n"
			"If you have a geforce 5x00+ or a radeon 9500+ and still\n"
			"get this message, try updating your graphics drivers."
		};
		fprintf(stderr, "%s\n", msg);
#if defined(WIN32) || defined(__WIN32__)
		SDL_Quit();
		MessageBox(0, msg, "error", MB_ICONERROR | MB_OK);
		exit(1);
#endif
		return -1;
	}

	glClearColor(0, 0, 0, 0);
	glClearDepth(1.0);
	glClearStencil(0);

	load_start = SDL_GetTicks();

	if(!(img = load_image("data/thelab.png", &img_x, &img_y))) {
		fprintf(stderr, "failed to load image\n");
		return -1;
	}
	glGenTextures(1, &splash_tex);
	glBindTexture(GL_TEXTURE_2D, splash_tex);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, 4, img_x, img_y, 0, GL_BGRA, GL_UNSIGNED_BYTE, img);

	if(!(startup_font = create_font("data/free_mono_bold.ttf", 18))) {
		fprintf(stderr, "failed to load font\n");
		return -1;
	}
	splash_alpha = 0.1;

	if(init_backdrop() == -1) {
		return -1;
	}
	splash_alpha = 0.3;
	if(init_bar() == -1) {
		return -1;
	}
	splash_alpha = 0.5;
	if(init_invtext() == -1) {
		return -1;
	}
	splash_alpha = 0.8;
	if(init_objects() == -1) {
		return -1;
	}
	splash_alpha = 1.0;

	while(SDL_GetTicks() - load_start < 3000) {
		glClear(GL_COLOR_BUFFER_BIT);
		if(!process_events()) return -1;
		draw_splash();
		SDL_GL_SwapBuffers();
		SDL_Delay(10);
	}

	if(music) {
		int res;
		startup_text("loading music...");
		if((res = sdlvf_init("data/music.ogg")) != 0) {
			startup_text("... failed");
			fprintf(stderr, "music playback error: %s\n", sdlvf_strerror(res));
			return -1;
		}
		atexit(sdlvf_done);
	}

	return 0;
}

int process_events(void)
{
	SDL_Event event;

	while(SDL_PollEvent(&event)) {
		switch(event.type) {
		case SDL_KEYDOWN:
			if(event.key.keysym.sym == 27) {
				return 0;
			}
			text_key_handler(event.key.keysym.sym);
			break;

		default:
			break;
		}
	}
	if(start_time > 0) redraw();

	return 1;
}

void redraw(void)
{
	unsigned int msec = SDL_GetTicks() - start_time;
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	draw_backdrop(msec);
	draw_objects(msec);
	if(msec > TM_S_BAR) {
		draw_bar(msec - TM_S_BAR);
	}
	if(msec > TM_S_TEXT) {
		draw_invtext(msec - TM_S_TEXT);
	}

	SDL_GL_SwapBuffers();

	if(music) {
		int res;
		if((res = sdlvf_check()) != SDLVF_PLAYING) {
			if(res == SDLVF_STOPPED) {
				sdlvf_seek(4.56);
			} else {
				fprintf(stderr, "music playback error: %s\n", sdlvf_strerror(res));
			}
		}
	}
}

void draw_splash(void)
{
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, splash_tex);

	glBegin(GL_QUADS);
	glColor4f(1, 1, 1, splash_alpha);
	glTexCoord2f(0, 1); glVertex2f(-1, -1);
	glTexCoord2f(1, 1); glVertex2f(1, -1);
	glTexCoord2f(1, 0); glVertex2f(1, 1);
	glTexCoord2f(0, 0); glVertex2f(-1, 1);
	glEnd();

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);
}

void startup_text(const char *txt)
{
	static const char *init_strings[25];
	static int init_str_top;
	int i;

	printf("%s\n", txt);

	init_strings[init_str_top++] = txt;

	bind_font(startup_font);
	set_text_pos(0, 30 * get_line_advance());

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	draw_splash();

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	set_text_color(1, 1, 1, 1);
	for(i=0; i<init_str_top; i++) {
		print_string(init_strings[i]);
		text_line_advance(1);
		text_cret();
	}

	glDisable(GL_BLEND);

	if(!process_events()) {
		exit(0);
	}
	SDL_GL_SwapBuffers();
}

void parse_args(int argc, char **argv)
{
	FILE *out;
	int i;

	for(i=1; i<argc; i++) {
		if(argv[i][0] == '-' && argv[i][2] == 0) {
			switch(argv[i][1]) {
			case 'f':
				fullscr = 1;
				break;

			case 'w':
				fullscr = 0;
				break;

			case 'm':
				music = !music;
				break;

			case 'd':
				if(isdigit(argv[++i][0])) {
					num_ducks = atoi(argv[i]);
				}
				break;

			case 'h':
				if(1) {
					out = stdout;
				} else {
			default:
					out = stderr;
				}
				fputs("usage: %s [options]\n", out);
				fputs("options:\n", out);
				fputs("  -f\trun in fullscreen (default)\n", out);
				fputs("  -w\trun in a window\n", out);
				fputs("  -m\tno music\n", out);
				fputs("  -h\tthis help thingy\n", out);
				exit(out == stdout ? 0 : EXIT_FAILURE);
			}
		} else {
			fprintf(stderr, "unexpected argument: %s\n", argv[i]);
			exit(EXIT_FAILURE);
		}
	}
}
